import os
import shutil
import tkinter as tk
from tkinter import filedialog, messagebox
from tkinter import ttk
import chardet
import re
import pyperclip


# 创建主窗口
root = tk.Tk()
root.title("批量重命名与复制文件")
root.update()
root.minsize(700, 550)     # 设置最小尺寸保证基础布局
root.geometry(f"{root.winfo_reqwidth()}x550")
root.config(bg="#f4f4f9")  # 设置背景色
# 禁止窗口拉伸
root.resizable(True, False)




# 设置默认路径
source_folder = ""
target_folder = ""
file_mapping = []

# 修改字体样式
font_style = ("Arial", 12)
button_font = ("Arial", 12, "bold")
label_font = ("Arial", 10)


# 选择源文件夹
def select_source_folder():
    global source_folder
    folder = filedialog.askdirectory(title="选择源文件夹")
    if folder:
        source_folder = folder
        source_label.config(text="源文件夹: " + source_folder)


def copy_source_filenames(source_folder):
    if not source_folder:
        messagebox.showwarning("警告", "请先选择源文件夹")
        return

    try:
        # 获取源文件夹下所有文件名（不包含子目录）
        filenames = [
            f for f in os.listdir(source_folder)
            if os.path.isfile(os.path.join(source_folder, f))
        ]

        if not filenames:
            messagebox.showinfo("提示", "源文件夹为空")
            return

        # 将文件名拼接为文本（每行一个文件名）
        filenames_text = "\n".join(filenames)

        # 复制到剪贴板
        pyperclip.copy(filenames_text)
        messagebox.showinfo("成功", f"已复制 {len(filenames)} 个文件名到剪贴板！")

    except Exception as e:
        messagebox.showerror("错误", f"无法复制文件名: {str(e)}")


# 选择目标文件夹
def select_target_folder():
    global target_folder
    folder = filedialog.askdirectory(title="选择目标文件夹")
    if folder:
        target_folder = folder
        target_label.config(text="目标文件夹: " + target_folder)


# 自动检测文件编码
def detect_encoding(filepath):
    with open(filepath, 'rb') as file:  # 使用二进制模式读取文件内容
        raw_data = file.read()
        result = chardet.detect(raw_data)
        encoding = result['encoding']
        confidence = result['confidence']

        # 如果信心度低于一定阈值，可以尝试其他常见编码
        if confidence < 0.5:
            print(f"警告: 编码检测信心度较低 ({confidence}), 尝试其他编码。")
            encoding = 'utf-8'  # 你可以根据需要调整备用编码列表
        return encoding


# 选择文件映射文件 (files.txt)
def load_file_mapping():
    global file_mapping
    filepath = filedialog.askopenfilename(filetypes=[("Text files", "*.txt")])

    if filepath:
        try:
            # 自动检测文件编码
            encoding = detect_encoding(filepath)
            print(f"检测到文件编码: {encoding}")

            # 使用检测到的编码打开文件
            with open(filepath, 'r', encoding=encoding) as file:
                file_mapping = []
                for line_num, line in enumerate(file, start=1):  # 逐行读取更高效
                    stripped_line = line.strip()
                    if not stripped_line:
                        continue  # 跳过空行

                    # 分割原文件名和目标文件名
                    parts = re.split(r'\s+', line.strip(), maxsplit=1)# 最多分割一次，避免文件名含空格的情况
                    if len(parts) == 2:
                        file_mapping.append(parts)
                    else:
                        # 格式错误的行，打印出错的行号和内容
                        print(f"格式错误的行：第{line_num}行 - '{line.strip()}'")
                        messagebox.showwarning("警告", f"文件格式错误：第{line_num}行：'{line.strip()}'")
                        return

                update_mapping_table()

        except Exception as e:
            messagebox.showerror("错误", f"读取文件映射文件失败: {str(e)}")

# 更新映射关系表格
def update_mapping_table():
    for row in mapping_tree.get_children():
        mapping_tree.delete(row)

    for idx, (source, new_name) in enumerate(file_mapping):
        mapping_tree.insert("", "end", values=(source, new_name))


# 保存编辑后的文件映射
def save_file_mapping():
    global file_mapping
    filepath = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files", "*.txt")])
    if filepath:
        try:
            with open(filepath, 'w', encoding='utf-8') as file:
                for source, new_name in file_mapping:
                    file.write(f"{source}\t{new_name}\n")
            messagebox.showinfo("成功", "文件映射已保存")
        except Exception as e:
            messagebox.showerror("错误", f"保存文件映射失败: {str(e)}")


# 编辑文件映射
def on_mapping_edit(event):
    item = mapping_tree.selection()[0]
    source, new_name = mapping_tree.item(item, "values")

    def save_edit():
        new_source = source_entry.get()
        new_new_name = new_name_entry.get()
        file_mapping[item_idx[0]] = [new_source, new_new_name]
        update_mapping_table()
        edit_window.destroy()

    item_idx = [mapping_tree.index(item)]

    edit_window = tk.Toplevel(root)
    edit_window.title("编辑文件映射")
    edit_window.geometry("400x200")
    edit_window.config(bg="#f4f4f9")

    tk.Label(edit_window, text="源文件名:", font=font_style, bg="#f4f4f9").grid(row=0, column=0, padx=20, pady=10,
                                                                                sticky="w")
    source_entry = tk.Entry(edit_window, font=font_style, width=40)
    source_entry.insert(0, source)
    source_entry.grid(row=0, column=1, padx=20, pady=10)

    tk.Label(edit_window, text="新文件名:", font=font_style, bg="#f4f4f9").grid(row=1, column=0, padx=20, pady=10,
                                                                                sticky="w")
    new_name_entry = tk.Entry(edit_window, font=font_style, width=40)
    new_name_entry.insert(0, new_name)
    new_name_entry.grid(row=1, column=1, padx=20, pady=10)

    save_button = tk.Button(edit_window, text="保存", font=button_font, bg="#4CAF50", fg="white", relief="flat",
                            command=save_edit)
    save_button.grid(row=2, columnspan=2, pady=15, padx=20)


# 执行文件复制和重命名操作
def execute_copy_rename():
    if not source_folder or not target_folder:
        messagebox.showerror("错误", "请先选择源文件夹和目标文件夹")
        return

    if not file_mapping:
        messagebox.showerror("错误", "请先加载文件映射")
        return

    # 确保目标文件夹存在
    if not os.path.exists(target_folder):
        os.makedirs(target_folder)

    try:
        for source_file, new_name in file_mapping:
            source_file_path = os.path.join(source_folder, source_file)
            target_file_path = os.path.join(target_folder, new_name)

            # 检查源文件是否存在
            if os.path.exists(source_file_path):
                shutil.copy(source_file_path, target_file_path)
            else:
                messagebox.showwarning("警告", f"文件 {source_file} 不存在")

        messagebox.showinfo("完成", "批量重命名和复制完成！")
    except Exception as e:
        messagebox.showerror("错误", f"发生错误: {str(e)}")


# 创建 UI 元素
frame = tk.Frame(root, bg="#f4f4f9")
frame.pack(pady=20, padx=20, fill="x")

# 设置布局的外观
frame.columnconfigure(0, weight=1)
frame.columnconfigure(1, weight=2)

# 源文件夹选择
source_button = tk.Button(frame, text="选择源文件夹", font=button_font, bg="#4CAF50", fg="white", relief="flat",
                          command=select_source_folder, width=20)
source_button.grid(row=0, column=0, padx=20, pady=10, sticky="w")
source_label = tk.Label(frame, text="源文件夹: 未选择", font=font_style, bg="#f4f4f9", anchor="w")
source_label.grid(row=0, column=1, padx=20, pady=10, sticky="w")

# 新增按钮：复制源文件夹文件名 ▼
copy_names_button = tk.Button(
    frame,
    text="复制文件名",
    font=button_font,
    bg="#9C27B0",  # 紫色区分功能
    fg="white",
    relief="flat",
    command=lambda: copy_source_filenames(source_folder),  # 绑定函数
    width=15
)
copy_names_button.grid(row=0, column=2, padx=10, pady=10, sticky="e")  # 右侧对齐


# 目标文件夹选择
target_button = tk.Button(frame, text="选择目标文件夹", font=button_font, bg="#4CAF50", fg="white", relief="flat",
                          command=select_target_folder, width=20)
target_button.grid(row=1, column=0, padx=20, pady=10, sticky="w")
target_label = tk.Label(frame, text="目标文件夹: 未选择", font=font_style, bg="#f4f4f9", anchor="w")
target_label.grid(row=1, column=1, padx=20, pady=10, sticky="w")

# 创建按钮框架，用于水平排列按钮
button_frame = tk.Frame(root, bg="#f4f4f9")
button_frame.pack(pady=20, padx=20, fill="x")

# 加载文件映射按钮
load_button = tk.Button(button_frame, text="加载文件映射", font=button_font, bg="#2196F3", fg="white", relief="flat",
                        command=load_file_mapping, width=20)
load_button.grid(row=0, column=0, padx=10, pady=15, sticky="w")

# 保存文件映射按钮
save_button = tk.Button(button_frame, text="保存文件映射", font=button_font, bg="#2196F3", fg="white", relief="flat",
                        command=save_file_mapping, width=20)
save_button.grid(row=0, column=1, padx=10, pady=10, sticky="w")

# 执行复制和重命名按钮
execute_button = tk.Button(button_frame, text="开始复制和重命名", font=button_font, bg="#FF5722", fg="white", relief="flat",
                           command=execute_copy_rename, width=20)
execute_button.grid(row=0, column=2, padx=10, pady=15, sticky="w")

# 显示文件映射关系的表格
columns = ("源文件名", "新文件名")
mapping_tree = ttk.Treeview(root, columns=columns, show="headings", height=10)
mapping_tree.heading("源文件名", text="源文件名")
mapping_tree.heading("新文件名", text="新文件名")
mapping_tree.pack(pady=20, fill="both", expand=True)

# 设置表格样式
mapping_tree.tag_configure('oddrow', background="#f9f9f9")
mapping_tree.tag_configure('evenrow', background="#ffffff")

# 双击表格行进行编辑
mapping_tree.bind("<Double-1>", on_mapping_edit)

# 运行 GUI
root.mainloop()